/*! \file */
/*
* Copyright (c) 2008-2011, Thomas Handorf, Nils Christian
* 
* This file is part of libScopes.
* libScopes is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* libScopes is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public License
* along with libScopes.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef th_scope_h
#define th_scope_h
#include "array.h"
#include "net.h"
template <class T> class __scope{
   public:
      __scope() : present(NULL), active(NULL) {};
      __scope(const __scope& st2) : present(NULL), active(NULL) {
         if (st2.present) present=st2.present->copy();
         if (st2.active) active=st2.active->copy();
      };
      __scope(array<T>* p ) : present(p), active(NULL) {};
      __scope(array<T>* p, array<T>* a) : present(p), active(a) {};
      ~__scope(){
         delete present;
         delete active;
      }
      array<T>* present; // present compounds
      array<T>* active; // active reactions
};

template <class T> class __state : public __scope<T>{
   public:
      __state() : __scope<T>(), depleted(NULL), blocking(NULL) {};
      __state(const __state& st2) : __scope<T>(st2), depleted(NULL), blocking(NULL) {
         if (st2.depleted) depleted=st2.depleted->copy();
         if (st2.blocking) blocking=st2.blocking->copy();
      };
      __state(array<T>* p, array<T>* d) : __scope<T>(p), depleted(d),blocking(NULL) {};
      __state(array<T>* p, array<T>* d, array<T>* a, array<T>* b) : __scope<T>(p,a), depleted(d), blocking(b) {};
      ~__state(){
         delete depleted;
         delete blocking;
      }
      array<T>* combine(){ // this returns the actual activity of the compounds; because depleted compounds are also present, but not active
         array<T>* cmb=this->present->copy();
         if (this->depleted) cmb->subSet(*(this->depleted));
         return cmb;
      }
      array<T>* combineReactionState(){ // this returns the actual activity of the compounds; because depleted compounds are also present, but not active
         array<T>* cmb=this->active->copy();
         if (this->blocking) cmb->subSet(*(this->blocking));
         return cmb;
      }
      // combine reactions not necessary, since blocking reactions are also active; simply retrieve active
      array<T>* depleted; // depleted compounds
      array<T>* blocking; // blocking reactions
};

typedef __state<unsigned char> State;
typedef __scope<unsigned char> Scope;
typedef __scope<size_type> ScopeExpansion;

//typedef VVS Channels;
class Channels : public VVS {
   public:
      Channels(Net* net){
         this->resize(net->numC());
      }
      ~Channels(){
         size_type i;
         for (i=0;i<this->size();i++){
            if ((*this)[i]) delete (*this)[i];
         }
      }
      void clear(){
         size_type i;
         for (i=0;i<this->size();i++){
            if ((*this)[i]) {
               delete (*this)[i];
               (*this)[i]=NULL;
            }
         }
      }
};
//typedef std::vector<State*> StateList;
class StateList : public std::vector<State*> {
   public:
      ~StateList(){
         size_type i;
         for (i=0;i<this->size();i++){
            if ((*this)[i]) delete (*this)[i];
         }
      }
      State* last(){
         return (*this)[this->size()-1];
      }
      bool cyclic;
      size_t cyclelen;
};
void dScopeStep(Net* net, VC* present, VC* depl, VC* active, VC* blocking, VC* seed=NULL, VC* block=NULL, Channels* chn=NULL, bool noi=false);//!< calculates one step of the algorithm
StateList* dScope(Net* net,size_t max,VC* seed=NULL,VC* block=NULL, Channels* chn=NULL, bool noi=false);//!< calculates a series of steps until a stable static or cyclic solution is reached
void dScopeRun(Net* net,size_t min,size_t max,StateList* scopes, VC* seed=NULL,VC* block=NULL, Channels* chn=NULL, bool noi=false);//!< continues calculating the series of steps
VC* scope(Net* net, VC* seed); //!< simply calculates the static scope
// should be replaced by fast static-scope routine 
template <typename T> __scope<T>* sScope(Net* net, array<T>* seed, bool exp=false);
#endif
